//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <ddk.h>
#include "ata.h"
#include "parttab.h"
#include "idectrlr.h"
#include "idedrive.h"
#include "idepart.h"

ECode IDEPartition::Read(
    /* [in] */ Int64 u64Offset,
    /* [in] */ Int32 bytesToRead,
    /* [out] */ MemoryBuf * pBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    if (pBuffer == NULL || !pBuffer->GetCapacity()
        || (int)bytesToRead > pBuffer->GetCapacity()
        || 0 == bytesToRead
        || 0 != (bytesToRead & SECTOR_MASK)
        || 0 != (u64Offset & SECTOR_MASK)) {
        return E_INVALID_ARGUMENT;
    }

    uint32_t u32OffsetSector = (uint32_t)(u64Offset >> SECTOR_SHIFT);

    uint32_t u32NumberOfSectorsToRead = bytesToRead >> SECTOR_SHIFT;

    if (m_pPartitionInfo->m_u32TotalSectors
        < u32OffsetSector + u32NumberOfSectorsToRead) {
//        kprintf("\n*ERROR*The number at the edge!\n");
        return E_INVALID_ARGUMENT;
    }

    uint_t uNumberOfSectorsRead;
    ECode ec = m_pDrive->ReadSectors(
        m_pPartitionInfo->m_u32StartSector + u32OffsetSector,
        (uint8_t *)pBuffer->GetPayload(),
        u32NumberOfSectorsToRead,
        &uNumberOfSectorsRead);

    pBuffer->SetUsed(uNumberOfSectorsRead << SECTOR_SHIFT);

    if (NULL != ppCompletionEvent) *ppCompletionEvent = NULL;
    return ec;
}

ECode IDEPartition::Write(
    /* [in] */ Int64 u64Offset,
    /* [in] */ const MemoryBuf & buffer,
    /* [out] */ Int32 * pBytesWritten,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    if (buffer.IsNullOrEmpty()
        || 0 != (buffer.GetUsed() & SECTOR_MASK)
        || 0 != (u64Offset & SECTOR_MASK)
        || NULL == pBytesWritten) {
        return E_INVALID_ARGUMENT;
    }

    uint32_t u32OffsetSector = (uint32_t)(u64Offset >> SECTOR_SHIFT);

    uint32_t u32NumberOfSectorsToWrite =
            (uint_t)buffer.GetUsed() >> SECTOR_SHIFT;

    if (m_pPartitionInfo->m_u32TotalSectors
        < u32OffsetSector + u32NumberOfSectorsToWrite) {
//        kprintf("\n*ERROR*The number at the edge!\n");
        return E_INVALID_ARGUMENT;
    }

    uint_t uNumberOfSectorsWritten;
    ECode ec = m_pDrive->WriteSectors(
        m_pPartitionInfo->m_u32StartSector + u32OffsetSector,
        (uint8_t *)buffer.GetPayload(),
        u32NumberOfSectorsToWrite,
        &uNumberOfSectorsWritten);

    *pBytesWritten = uNumberOfSectorsWritten << SECTOR_SHIFT;

    if (NULL != ppCompletionEvent) *ppCompletionEvent = NULL;
    return ec;
}

ECode IDEPartition::Control(
    /* [in] */ Handle32 nControlCode,
    /* [in] */ const MemoryBuf & inBuffer,
    /* [out] */ MemoryBuf * pOutBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    // TODO:
    return E_NOT_IMPLEMENTED;
}

void IDEPartition::Dispose()
{
    delete this;
}

IDEPartition::IDEPartition(IDEDrive *pDrive, uint_t uDeviceNo)
{
    assert(pDrive);
    m_pDrive    = pDrive;
    m_uDeviceNo = uDeviceNo;

    m_pPartitionInfo = m_pDrive->GetPartitionInfo(uDeviceNo);
    assert(m_pPartitionInfo);
}

EXTERN IDeviceDriver * CDECL CreateIDEPartition(uint_t uDeviceNo,
                void *pvParameter)
{
    assert(pvParameter);

    IDEPartition *pIDEPartition =
            new IDEPartition ((IDEDrive *)pvParameter, uDeviceNo);
    if (NULL == pIDEPartition) return NULL;

    pIDEPartition->AddRef();

    return pIDEPartition;
}
